Header file deferred_construction.hpp

namespace type_safe
{
    template <typename T>
    class deferred_construction;
}

Class template type_safe::deferred_construction

template <typename T>
class deferred_construction
{
public:
    using value_type = T;
    
    deferred_construction() noexcept;
    
    deferred_construction(const deferred_construction& other);
    
    deferred_construction(deferred_construction&& other) noexcept('hidden');
    
    deferred_construction(value_type) = delete;
    
    ~deferred_construction() noexcept;
    
    deferred_construction& operator=(deferred_construction) = delete;
    
    template <typename U>
    deferred_construction& operator=(U&& u);
    
    //=== Modifiers ===//
    template <typename ... Args>
    void emplace(Args&&... args);
    
    //=== Observers ===//
    bool has_value() const noexcept;
    
    operator bool() const noexcept;
    
    value_type& value() & noexcept;
    const value_type& value() const & noexcept;
    value_type&& value() && noexcept;
    const value_type&& value() const && noexcept;
};

A tiny wrapper to create an object without constructing it yet.

This is useful if you have a type that is default constructible, but can't be initialized properly - yet. It works especially well with ts::output_parameter.

It has two states: Either it is initialized in which case you can get its value, or it is un-initialized in which case you cannot get its value. All objects start out un-initialized. For consistency with ts::basic_optional it provides a similar interface, yet it is not as flexible and does not allow to reset it to the uninitialized state, once initialized.

Default constructor type_safe::deferred_construction::deferred_construction

deferred_construction() noexcept;

Default constructor.

Effects: Creates it in the un-initialized state.

Copy constructor type_safe::deferred_construction::deferred_construction

deferred_construction(const deferred_construction& other);

Copy constructor:

Effects: If other is un-initialized, it will be un-initialized as well. If other is initialized, it will copy the stored value.

Throws: Anything thrown by the copy constructor of value_type if other is initialized.

Move constructor type_safe::deferred_construction::deferred_construction

deferred_construction(deferred_construction&& other) noexcept('hidden');

Move constructor:

Effects: If other is un-initialized, it will be un-initialized as well. If other is initialized, it will copy the stored value.

Throws: Anything thrown by the move constructor of value_type if other is initialized.

Notes: other will still be initialized after the move operation, it is just in a moved-from state.

Constructor type_safe::deferred_construction::deferred_construction

deferred_construction(value_type) = delete;

Notes: You cannot construct it from the type directly. If you are able to do that, there is no need to use defer_construction!

Destructor type_safe::deferred_construction::~deferred_construction

~deferred_construction() noexcept;

Effects: If it is initialized, it will destroy the value. Otherwise it has no effect.

Assignment operator type_safe::deferred_construction::operator=

deferred_construction& operator=(deferred_construction) = delete;

Notes: You cannot copy or move assign it. This is a deliberate design decision to guarantee, that an initialized object stays initialized, no matter what.

Assignment operator type_safe::deferred_construction::operator=

template <typename U>
deferred_construction& operator=(U&& u);

Effects: Same as emplace(std::forward<U>(u)).

Requires: value_type must be constructible from U.

Notes: You must not use this function to actually "assign" the value, like emplace(), the object must not be initialized.

Function template type_safe::deferred_construction::emplace

template <typename ... Args>
void emplace(Args&&... args);

Effects: Initializes the object with the value_type constructed from args.

Requires: has_value() == false.

Throws: Anything thrown by the chosen constructor of value_type.

Notes: You must only call this function once, after the object has been initialized, you can use value() to assign to it.

Function type_safe::deferred_construction::has_value

bool has_value() const noexcept;

Returns: true if the object is initialized, false otherwise.

Conversion operator type_safe::deferred_construction::operator bool

operator bool() const noexcept;

Returns: The same as has_value().

Function type_safe::deferred_construction::value

(1)  value_type& value() & noexcept;

(2)  const value_type& value() const & noexcept;

(3)  value_type&& value() && noexcept;

(4)  const value_type&& value() const && noexcept;

Access the stored value.

Returns: A (const) (rvalue) reference to the stored value.

Requires: has_value() == true.